<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Exercise - Colors</title>
    <link type="text/css" href="../resources/webgl-tutorials.css" rel="stylesheet" />
    <style>
        canvas {
            display: block;
            width: 100vw;
            height: 100vh;
        }

        body {
            font-family: Sans-Serif;
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>

</html>
<script id="color-vertex-shader" type="x-shaedr/x-vertex">
attribute vec3 a_position;

uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;

void main(){
    gl_Position = u_projection * u_view * u_model * vec4(a_position * vec3(1, -1, 1), 1);
}
</script>
<script id="color-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

uniform vec3 u_objectColor;
uniform vec3 u_lightColor;

void main(){
    gl_FragColor = vec4(u_lightColor * u_objectColor, 1);
}
</script>
<script id="lamp-vertex-shader" type="x-shader/x-vertex">
attribute vec3 a_position;

uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;

void main(){
    gl_Position=u_projection * u_view * u_model * vec4(a_position * vec3(1, -1, 1), 1);
}
</script>
<script id="lamp-fragment-shader" type="x-shader/x-fragment">
    void main(){
        gl_FragColor = vec4(1);
    }
</script>
<script type="module">
    "use strict";

    import webglUtils from '../resources/webglUtils.js';
    import glm from '../resources/glm.js';

    let cameraPosition = [0, 0, 3];
    let cameraFront = [0, 0, -1];
    let cameraUp = [0, 1, 0];
    let deltaTime = 0;
    let lastFrame = 0;

    let lastX, lastY;
    let yaw = -90;
    let pitch = 0;
    let fov = 45;

    let lightPos = [1.2, 1, 2];

    function main() {

        /**@type {HTMLCanvasElement} */
        let canvas = document.getElementById("canvas"); document.onkeydown = (event) => {
            /**@type {KeyboardEvent} */
            var e = event || window.event || arguments.callee.caller.arguments[0];
            let cameraSpeed = 2.5 * deltaTime;
            if (e && e.keyCode == 87) { // 按 W 
                cameraPosition[0] += cameraSpeed * cameraFront[0];
                cameraPosition[1] += cameraSpeed * cameraFront[1];
                cameraPosition[2] += cameraSpeed * cameraFront[2];
                // console.log('wwwww');
            } else if (e && e.keyCode == 83) { // 按 S 
                cameraPosition[0] -= cameraSpeed * cameraFront[0];
                cameraPosition[1] -= cameraSpeed * cameraFront[1];
                cameraPosition[2] -= cameraSpeed * cameraFront[2];
                // console.log('sssss');
            } else if (e && e.keyCode == 65) { // A
                // console.log('aaaaa');
                cameraPosition[0] -= glm.normalize(glm.cross(cameraFront, cameraUp))[0] * cameraSpeed;
                cameraPosition[1] -= glm.normalize(glm.cross(cameraFront, cameraUp))[1] * cameraSpeed;
                cameraPosition[2] -= glm.normalize(glm.cross(cameraFront, cameraUp))[2] * cameraSpeed;
            } else if (e && e.keyCode == 68) { // D
                // console.log('ddddd');
                cameraPosition[0] += glm.normalize(glm.cross(cameraFront, cameraUp))[0] * cameraSpeed;
                cameraPosition[1] += glm.normalize(glm.cross(cameraFront, cameraUp))[1] * cameraSpeed;
                cameraPosition[2] += glm.normalize(glm.cross(cameraFront, cameraUp))[2] * cameraSpeed;
            }
            drawScene();
        }

        canvas.onmousedown = (e) => {
            lastX = e.clientX;
            lastY = e.clientY;
            fndown(e);
        }
        /**@param {MouseEvent} event */
        function fndown(event) {
            canvas.onmousemove = (e) => {
                let offsetX = e.clientX - lastX;
                let offsetY = lastY - e.clientY;

                lastX = e.clientX;
                lastY = e.clientY;

                // lastdom.innerHTML = ("(" + offsetX + " " + offsetY + ")");
                let sensitivity = 0.1;
                offsetX *= sensitivity;
                offsetY *= sensitivity
                yaw += offsetX;
                pitch += offsetY;

                let x = Math.cos(glm.radians(yaw)) * Math.cos(glm.radians(pitch));
                let y = Math.sin(glm.radians(pitch));
                let z = Math.sin(glm.radians(yaw)) * Math.cos(glm.radians(pitch));
                cameraFront = glm.normalize([x, y, z]);
                drawScene();
                console.log("ondrag");
            }
            canvas.onmouseup = (e) => {
                canvas.onmousemove = null;
                console.log("up");
            }
        }

        canvas.onwheel = (e) => {
            let offsetY = e.deltaY * 0.1;
            if (fov >= 1.0 && fov <= 45.0)
                fov += offsetY;
            if (fov <= 1.0)
                fov = 1.0;
            if (fov >= 45.0)
                fov = 45.0;
            drawScene();
        }

        let gl = canvas.getContext("webgl");
        if (!gl) {
            return;
        }

        let lightingShader = webglUtils.createProgramFromSecripts(gl, ["color-vertex-shader", "color-fragment-shader"]);
        let lampShader = webglUtils.createProgramFromSecripts(gl, ["lamp-vertex-shader", "lamp-fragment-shader"]);

        let vertices = [
            -0.5, -0.5, -0.5,
            0.5, -0.5, -0.5,
            0.5, 0.5, -0.5,
            0.5, 0.5, -0.5,
            -0.5, 0.5, -0.5,
            -0.5, -0.5, -0.5,

            -0.5, -0.5, 0.5,
            0.5, -0.5, 0.5,
            0.5, 0.5, 0.5,
            0.5, 0.5, 0.5,
            -0.5, 0.5, 0.5,
            -0.5, -0.5, 0.5,

            -0.5, 0.5, 0.5,
            -0.5, 0.5, -0.5,
            -0.5, -0.5, -0.5,
            -0.5, -0.5, -0.5,
            -0.5, -0.5, 0.5,
            -0.5, 0.5, 0.5,

            0.5, 0.5, 0.5,
            0.5, 0.5, -0.5,
            0.5, -0.5, -0.5,
            0.5, -0.5, -0.5,
            0.5, -0.5, 0.5,
            0.5, 0.5, 0.5,

            -0.5, -0.5, -0.5,
            0.5, -0.5, -0.5,
            0.5, -0.5, 0.5,
            0.5, -0.5, 0.5,
            -0.5, -0.5, 0.5,
            -0.5, -0.5, -0.5,

            -0.5, 0.5, -0.5,
            0.5, 0.5, -0.5,
            0.5, 0.5, 0.5,
            0.5, 0.5, 0.5,
            -0.5, 0.5, 0.5,
            -0.5, 0.5, -0.5
        ];

        webglUtils.resizeCanvasToDisplaySize(canvas);
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

        gl.enable(gl.DEPTH_TEST);

        let lightingPositionAttributeLocation = gl.getAttribLocation(lightingShader, "a_position");
        let positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        gl.enableVertexAttribArray(lightingPositionAttributeLocation);
        gl.vertexAttribPointer(lightingPositionAttributeLocation, 3, gl.FLOAT, false, 3 * 4, 0);

        let lampPositionAttributeLocation = gl.getAttribLocation(lampShader, "a_position");
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.enableVertexAttribArray(lampPositionAttributeLocation);
        gl.vertexAttribPointer(lampPositionAttributeLocation, 3, gl.FLOAT, false, 3 * 4, 0);

        gl.useProgram(lightingShader);
        let lightColorLocation = gl.getUniformLocation(lightingShader, "u_objectColor");
        let objectColorLocation = gl.getUniformLocation(lightingShader, "u_lightColor");

        gl.uniform3fv(objectColorLocation, [1.0, 0.5, 0.31]);
        gl.uniform3fv(lightColorLocation, [1.0, 1.0, 1.0]);

        let lightingModelLocation = gl.getUniformLocation(lightingShader, "u_model");
        let lightingViewLocation = gl.getUniformLocation(lightingShader, "u_view");
        let lightingProjectionLocation = gl.getUniformLocation(lightingShader, "u_projection");

        gl.useProgram(lampShader);

        let lampModelLocation = gl.getUniformLocation(lampShader, "u_model");
        let lampViewLocation = gl.getUniformLocation(lampShader, "u_view");
        let lampProjectionLocation = gl.getUniformLocation(lampShader, "u_projection");

        function drawScene() {

            gl.clearColor(0.2, 0.3, 0.3, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

            gl.useProgram(lightingShader);

            let center = [cameraPosition[0] + cameraFront[0], cameraPosition[1] + cameraFront[1], cameraPosition[2] + cameraFront[2]]
            let view = glm.lookAt(cameraPosition, center, cameraUp);
            view = glm.inverse(view);

            let aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
            let projection = glm.perspective(Math.PI * fov / 180, aspect, 1, 2000);
            gl.uniformMatrix4fv(lightingViewLocation, false, view);
            gl.uniformMatrix4fv(lightingProjectionLocation, false, projection);
            let model = glm.identity();
            gl.uniformMatrix4fv(lightingModelLocation, false, model);

            gl.drawArrays(gl.TRIANGLES, 0, 36);

            gl.useProgram(lampShader);
            gl.uniformMatrix4fv(lampProjectionLocation, false, projection);
            gl.uniformMatrix4fv(lampViewLocation, false, view);
            model = glm.translate(model, lightPos[0], lightPos[1], lightPos[2]);
            model = glm.scale(model, 0.2, 0.2, 0.2);
            gl.uniformMatrix4fv(lampModelLocation, false, model);

            gl.drawArrays(gl.TRIANGLES, 0, 36);
        }


        function getTime(time) {

            let currentFrame = time;
            deltaTime = (currentFrame - lastFrame) * 0.001;
            lastFrame = currentFrame;

            requestAnimationFrame(getTime);
        }
        drawScene();
        requestAnimationFrame(getTime);
    }

    main();


</script>